package MyFramePro.Aspect;


import MyFramePro.Annotation.SystemLog;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * 这里为切面类
 */
@Slf4j
@Aspect //表示该类为切面类
@Component
public class AspectLog {

    /**
     * @annotation 表示一种特殊标记，被定义的数据可以在编译、类加载、运行时被读取
     */
    @Pointcut(value = "@annotation(MyFramePro.Annotation.SystemLog)")   //这里表示被 SystemLog 注解所标注的方法，都会进行日志的打印与记录
    public void myPointCut(){}


    @Around("myPointCut()") //环绕通知
    public Object printLog(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        Object proceed;
        try {
            handleBefore(proceedingJoinPoint); //环绕的前置通知

            proceed = proceedingJoinPoint.proceed();    //表示被增强的方法执行的位置

            handleAfter(proceed);  //环绕的后置通知
        } finally {

            log.info("=======End=======" + System.lineSeparator()); // 结束后换行
        }
        return proceed;
    }


    /**
     *  环绕的前置通知
     */
    private void handleBefore(ProceedingJoinPoint proceedingJoinPoint) {

        ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = requestAttributes.getRequest();    //获取当前线程中的 request 对象

        SystemLog systemLog=getSystemLog(proceedingJoinPoint);  //获取被增强方法上的注解对象

        log.info("=======Start=======");
        // 打印请求 URL
        log.info("URL            : {}",request.getRequestURL());
        // 打印描述信息
        log.info("BusinessName   : {}",systemLog.businessName());   //根据注解对象获取到对应的属性值
        // 打印 Http method
        log.info("HTTP Method    : {}",request.getMethod());
        // 打印调用 controller 的全路径以及执行方法
        log.info("Class Method   : {}.{}",
                proceedingJoinPoint.getSignature().getDeclaringTypeName(), proceedingJoinPoint.getSignature().getName());
        // 打印请求的 IP
        log.info("IP             : {}",request.getRemoteHost());
        // 打印请求入参
        log.info("Request Args   : {}", JSON.toJSONString(proceedingJoinPoint.getArgs()));
    }

    /**
     * 环绕的后置通知
     */
    private void handleAfter(Object proceed) {

        // 打印出参
        log.info("Response       : {}",JSON.toJSONString(proceed));
    }


    /**
     * 该方法是获取被增强方法上的注解对象
     */
    private SystemLog getSystemLog(ProceedingJoinPoint joinPoint) {

        MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
        SystemLog systemLog = methodSignature.getMethod().getAnnotation(SystemLog.class);

        return systemLog;
    }

}
